//holds all the define statements
#include "Definitions.h"

//***Start things that have to be in main
HINSTANCE hInst;				// holds the instance for this app
HWND wndHandle;					// global window handle

// timer stuff
LARGE_INTEGER timeStart;
LARGE_INTEGER timeEnd;
LARGE_INTEGER timerFreq;
float         anim_rate;

// this holds the DirectX Manager
dxManager *dxMgr;

//directX global variables
HRESULT                 lastResult;
HRESULT					hResult;
LPDIRECT3D9             pD3D;
LPDIRECT3DDEVICE9       pd3dDevice;



// this is the surface that will hold the sprites
IDirect3DSurface9* spriteSurface;
IDirect3DSurface9* enemySurface;
IDirect3DSurface9* bkgrd;
IDirect3DSurface9* health;


int cas = 0;

// this is the sprite structure
//to be used later in the player class and also the zombie class

//player sprite struct
struct {
	RECT srcRect;				// holds the location of this sprite
								// in the source bitmap

	float posX;					// the sprites X position
	float posY;					// the sprites Y position

	// movement
	float moveX;
	float moveY;

	// animation
	int numFrames;				// number of frames this animation has
	int curFrame;				// the current frame of animation
	
} spriteStruct[MAX_SPRITES];

//zombie sprite struct
struct 
{
	RECT srcERect; //hold location of enemy sprite

	float ePosX;   //the enemy sprites x and y position
	float ePosY;

	float eMoveX;  //the enemy sprites movement
	float eMoveY;

	int numEFrames; //number of animation frames
	int curEFrame;  //the current frame of animation

} spriteEnemy[MAX_ENEMY_SPRITES];


RECT src, dest; //health RECT
RECT srcH[3], destH[3];
////////////////////////////////////////////// forward declarations
bool    initWindow(HINSTANCE hInstance);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
bool initDirect3D(HWND hwnd);


// sprite functions
bool initSprites(void); //initialize player sprite
bool initEnemy(void); //initialize enemy sprites
bool initMap();
bool initHealth();

void drawSprite(int whichOne); //rendering/drawing the hero sprite
void drawEnemy(int whichEn); //rendering/drawing the zombie sprite
void drawMap(void); //draw the map
void drawHealth();


//the main for directX
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	// call our function to init and create our window
	if (!initWindow(hInstance))
	{
		MessageBox(NULL, "Unable to create window", "ERROR", MB_OK);
		return false;
	}
	
	if(!initDirect3D(wndHandle))
	{
		return false;
	}
	
	// create the directx manager
	dxMgr = new dxManager();
	
	// init the directx manager
	if (!dxMgr->init(wndHandle))
	{
		MessageBox(NULL, "Unable to Init the DirectX Manager", "ERROR", MB_OK);
		return false;
	}

	// calls init sprites and checks to see if it works at the same time
	if (!initSprites())
	{
		MessageBox(NULL, "Unable to Init the player sprite", "ERROR", MB_OK);
		return false;
	}

	if(!initEnemy())
	{
		MessageBox(NULL, "Unable to Init the enemy sprites", "ERROR", MB_OK);
		return false;
	}

	if(!initMap())
	{
		MessageBox(NULL, "Unable to Init the map", "ERROR", MB_OK);
		return false;
	}

	if(!initHealth())
	{
		MessageBox(NULL, "Unable to Init the health bar", "ERROR", MB_OK);
		return false;
	}

	QueryPerformanceFrequency(&timerFreq);

	// Main message loop:
	// Enter the message loop
    MSG msg; 
    ZeroMemory( &msg, sizeof(msg) );
    while( msg.message!=WM_QUIT )
    {
		// check for messages
		if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
        {
			TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
		// this is called when no messages are pending
		else
		{
			//this entire code in this else statement is basically saying draw
			//whatever sprites need to be drawn in between beginRender() and endRender()
		QueryPerformanceCounter(&timeStart);
			
	
		//prepare the scene for display
		dxMgr->beginRender();
		

		//draw the sprites
			drawMap();
			drawSprite(0);
			drawEnemy(0);
			drawEnemy(1);
			drawHealth();
	
		
			//present the screen
		dxMgr->endRender();
	QueryPerformanceCounter(&timeEnd);
		

		anim_rate = ((float)timeEnd.QuadPart - (float)timeStart.QuadPart )/ timerFreq.QuadPart;
		}
		
    }

	// shutdown the directX Manager
	dxMgr->shutdown();

	return (int) msg.wParam;
}

bool initWindow(HINSTANCE hInstance) //initializes DirectX window
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= (WNDPROC)WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= 0;
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= NULL;
	wcex.lpszClassName	= "Zombies The Reckoning";
	wcex.hIconSm		= 0;
	RegisterClassEx(&wcex);

	wndHandle = CreateWindow("Zombies The Reckoning", 
							 "Zombies The Reckoning", 
							 WS_OVERLAPPEDWINDOW,
							 CW_USEDEFAULT, 
							 CW_USEDEFAULT, 
							 640, 
							 480, 
							 NULL, 
							 NULL, 
							 hInstance, 
							 NULL);
   if (!wndHandle)
      return false;
   
   ShowWindow(wndHandle, SW_SHOW);
   UpdateWindow(wndHandle);

   return true;
}




//This is where user input is taken in 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{
	switch (message) 
	{
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		case WM_KEYDOWN:
			switch (wParam)
			{
			/*case (('D') && ('W')):
				{
					cas = 9;
					break;
				}*/
			case 'W':
			case 38: //up
				{
				cas = 0;
				break;
				}
			case 'S':
			case 40: //down
				{
				cas = 1;
				break;
				}
			case 'A':
			case 37: //left
				{
				cas = 2;
				break;
				}
			case 'D':
			case 39: //right
				{
				cas = 3;
				break;
				}
			case VK_ESCAPE : //escape key pressed, exit the program
				PostQuitMessage(0);
				break;
			default:
				{
					cas = 5;
					break;
				}
			}
			break;
	}
	return DefWindowProc(hWnd, message, wParam, lParam);
}


bool initSprites(void)//initialize sprites
{
	spriteSurface = dxMgr->getSurfaceFromBitmap("./mccopy.bmp", 276, 78);
	if (spriteSurface == NULL)
		return false;
	/*if (enemySurface == NULL)
		return false;*/
	for (int i = 0; i < MAX_SPRITES; i++)
	{
		spriteStruct[i].srcRect.top = 0;
		spriteStruct[i].srcRect.left = i * 40;
		spriteStruct[i].srcRect.right = spriteStruct[i].srcRect.right + 40;//spriteStruct[i].srcRect.left + 40;
		spriteStruct[i].srcRect.bottom = spriteStruct[i].srcRect.top + 40;//40;

		//will replace the functions below with player get functions
		spriteStruct[i].posX = float(rand()%600);
		spriteStruct[i].posY = float(rand()%430);

		// set the animation data
		spriteStruct[i].curFrame = 0;
		spriteStruct[i].numFrames = 4;

		// set the move data
		spriteStruct[i].moveX = 0.0;//40.0;
		spriteStruct[i].moveY = 0.0;	
	}
	return true;
}

bool initEnemy(void)
{

	enemySurface = dxMgr->getSurfaceFromBitmap("./dzcopy.bmp", 189, 78);
	/*enemySurface = getSurfaceFromBitmap("./dz.bmp");*/


	if (enemySurface == NULL)
		return false;

	for (int i=0; i < MAX_ENEMY_SPRITES; i++)
	{
		spriteEnemy[i].srcERect.top = 0;
		spriteEnemy[i].srcERect.left = i * SPRITE_WIDTH;
		spriteEnemy[i].srcERect.right = spriteStruct[i].srcRect.left + SPRITE_WIDTH;
		spriteEnemy[i].srcERect.bottom = SPRITE_HEIGHT;
		spriteEnemy[i].ePosX = float (rand()% SCRN_WIDTH - SPRITE_WIDTH);
		spriteEnemy[i].ePosY = float (rand()% SCRN_HEIGHT - SPRITE_HEIGHT);

		// set the animation data
		spriteEnemy[i].curEFrame = 0;
		spriteEnemy[i].numEFrames = 3;

		// set the move data
		spriteEnemy[i].eMoveX = 20;
		spriteEnemy[i].eMoveY = 0;
	}
	return true;
}


//player sprite
void drawSprite(int whichOne)
{

	// set the source rect to the correct frame position
	spriteStruct[whichOne].srcRect.top = 0;
	spriteStruct[whichOne].srcRect.bottom = spriteStruct[whichOne].srcRect.top + 78;
	spriteStruct[whichOne].srcRect.left = spriteStruct[whichOne].curFrame * 69;
	spriteStruct[whichOne].srcRect.right = spriteStruct[whichOne].srcRect.left + 69;
	
	// move the sprite by it's movement rate
	spriteStruct[whichOne].posX += spriteStruct[whichOne].moveX * (anim_rate* 6);
	spriteStruct[whichOne].posY += spriteStruct[whichOne].moveY * (anim_rate* 6);
	
	// make sure that this sprite is not going off the screen 
	//with the upcoming if statements

	if (spriteStruct[whichOne].posX > MAX_LOCX)
	{
		spriteStruct[whichOne].posX = MAX_LOCX;
	}

	if (spriteStruct[whichOne].posX < 0)
	{
		spriteStruct[whichOne].posX = 0.0;
	}

	if (spriteStruct[whichOne].posY > MAX_LOCY)
	{
		spriteStruct[whichOne].posY = MAX_LOCY;
	}

	if (spriteStruct[whichOne].posY < 40)
	{
		spriteStruct[whichOne].posY = 40.0;
	}

    //the next set of if statements makes it so that it changes 
    //what sprite is being displayed depending on the key press
	//after the key is pressed cas is reset to a different number
	//to stop the sprite from moving and retaining its direction
	if (cas == 0) //w
	{
		if (spriteStruct[whichOne].posY <= 0)
		{
			spriteStruct[whichOne].moveX = 0.0;//40.0;
			spriteStruct[whichOne].moveY = 0.0;
			spriteStruct[whichOne].curFrame = 0; //sets the current sprite animation frame
		}
		else
		{
			spriteStruct[whichOne].moveX = 0.0;//40.0;
			spriteStruct[whichOne].moveY = -120.0;
			spriteStruct[whichOne].curFrame = 0;	
			cas = 5;
		}

	}
	else if (cas == 1) //s
	{
		
		if (spriteStruct[whichOne].posY >= MAX_LOCY)
		{
			spriteStruct[whichOne].moveX = 0.0;//40.0;
			spriteStruct[whichOne].moveY = 0.0;
			spriteStruct[whichOne].curFrame = 1;
		}
		else
		{
			spriteStruct[whichOne].moveX = 0.0;//40.0;
			spriteStruct[whichOne].moveY = 120.0;
			spriteStruct[whichOne].curFrame = 1;
			cas = 6;
		}
	}
	else if (cas == 2) //a
	{
		if (spriteStruct[whichOne].posX <= 0)
		{
			spriteStruct[whichOne].moveX = 0.0;//40.0;
			spriteStruct[whichOne].moveY = 0.0;
			spriteStruct[whichOne].curFrame = 2;
		}
		else
		{
			spriteStruct[whichOne].moveX = -120.0;//40.0;
			spriteStruct[whichOne].moveY = 0.0;
			spriteStruct[whichOne].curFrame = 2;
			cas = 7;
		}
	}
	else if (cas == 3) //d
	{
		if (spriteStruct[whichOne].posX >= MAX_LOCX)
		{
			spriteStruct[whichOne].moveX = 0.0;//40.0;
			spriteStruct[whichOne].moveY = 0.0;
			spriteStruct[whichOne].curFrame = 3;
		}
		else
		{
			spriteStruct[whichOne].moveX = 120.0;// 40.0;
			spriteStruct[whichOne].moveY = 0.0;
			spriteStruct[whichOne].curFrame = 3;
			cas = 8;
		}
	}

///////////////////////////////////////////////////////////////////////////////
//series of checks to stop the character from moving and fixing his direction.
//////////////////////////////////////////////////////////////////////////////

else if (cas == 5) //after cas moves the sprite in a direction, stop it and retain the sprite image
	{
		if (spriteStruct[whichOne].posX >= MAX_LOCX)
		{
			spriteStruct[whichOne].moveX = 0.0;//40.0;
			spriteStruct[whichOne].moveY = 0.0;
			spriteStruct[whichOne].curFrame = 0;
		}
		else
		{
			spriteStruct[whichOne].moveX = 0.0;// 40.0;
			spriteStruct[whichOne].moveY = 0.0;
			spriteStruct[whichOne].curFrame = 0;
		}
	}

	else if (cas == 6) //after s is hit
	{
		if (spriteStruct[whichOne].posX >= MAX_LOCX)
		{
			spriteStruct[whichOne].moveX = 0.0;//40.0;
			spriteStruct[whichOne].moveY = 0.0;
			spriteStruct[whichOne].curFrame = 1;
		}
		else
		{
			spriteStruct[whichOne].moveX = 0.0;// 40.0;
			spriteStruct[whichOne].moveY = 0.0;
			spriteStruct[whichOne].curFrame = 1;
		}
	}

else if (cas == 7) //after a is hit
	{
		if (spriteStruct[whichOne].posX >= MAX_LOCX)
		{
			spriteStruct[whichOne].moveX = 0.0;//40.0;
			spriteStruct[whichOne].moveY = 0.0;
			spriteStruct[whichOne].curFrame = 2;
		}
		else
		{
			spriteStruct[whichOne].moveX = 0.0;// 40.0;
			spriteStruct[whichOne].moveY = 0.0;
			spriteStruct[whichOne].curFrame = 2;
		}
	}

	else if (cas == 8) //after d is hit
	{
		if (spriteStruct[whichOne].posX >= MAX_LOCX)
		{
			spriteStruct[whichOne].moveX = 0.0;//40.0;
			spriteStruct[whichOne].moveY = 0.0;
			spriteStruct[whichOne].curFrame = 3;
		}
		else
		{
			spriteStruct[whichOne].moveX = 0.0;// 40.0;
			spriteStruct[whichOne].moveY = 0.0;
			spriteStruct[whichOne].curFrame = 3;
		}
	}


	// set the destination for the player sprite
	RECT destRect;
	destRect.left = int(spriteStruct[whichOne].posX);
	destRect.top = int(spriteStruct[whichOne].posY);
	destRect.bottom = destRect.top + PLAYER_HEIGHT;
	destRect.right = destRect.left + PLAYER_WIDTH;	

	// draw player sprite to back buffer
	dxMgr->blitToSurface(spriteSurface, &spriteStruct[whichOne].srcRect, &destRect);
}

//enemy sprite
void drawEnemy(int whichEn)
{
	
	
	// set the source rect to the correct frame position
	spriteEnemy[whichEn].srcERect.top = 0;
	spriteEnemy[whichEn].srcERect.bottom = spriteEnemy[whichEn].srcERect.top + 78;
	spriteEnemy[whichEn].srcERect.left = spriteEnemy[whichEn].curEFrame * 63;
	spriteEnemy[whichEn].srcERect.right = spriteEnemy[whichEn].srcERect.left + 63;

	//***Begin Enemy Movement

	// move the enemy sprite by it's movement rate
	spriteEnemy[whichEn].ePosX += spriteEnemy[whichEn].eMoveX;

	// make sure that this enemy sprite is not going off the screen
	if (spriteEnemy[whichEn].ePosX > SCRN_WIDTH - SPRITE_WIDTH)
	{
		spriteEnemy[whichEn].eMoveX = -2;
		spriteEnemy[whichEn].curEFrame = 2; //change the frames
	}
	else if (spriteEnemy[whichEn].ePosX < 0)
	{
		spriteEnemy[whichEn].eMoveX = 2;
		spriteEnemy[whichEn].curEFrame = 1;
	}

	//***End Enemy Movement

	// set the destination for the enemy sprite
	RECT destERect;
	destERect.left = long (spriteEnemy[whichEn].ePosX);
	destERect.top  = long (spriteEnemy[whichEn].ePosY);
	destERect.bottom = destERect.top + SPRITE_HEIGHT;
	destERect.right = destERect.left + SPRITE_WIDTH;

	// draw enemy sprite to the back buffer
	dxMgr->blitToSurface(enemySurface, &spriteEnemy[whichEn].srcERect, &destERect);
}

//Checking4Collision()
//{
//	float AngleCheck =sqrt(pow(spriteStruct[whichOne].posX*spriteEnemy[whichEn].ePosX),2)+pow(spriteStruct[whichOne].posY*spriteEnemy[whichEn].ePosY),2));
//	if(AngleCheck>=0||AngleCheck<90)
//	{
//		float distanceCheck = sqrt(pow(spriteStruct[whichOne].posX*spriteEnemy[whichEn].ePosX),2)+pow(spriteStruct[whichOne].posY*spriteEnemy[whichEn].ePosY),2));
//		if(distanceCheck>=0||distanceCheck<=20)
//		{
//			HealthCount=HealthCount-1;
//			if(HealthCount==0)
//			{
//				exit(); // GAME OVER No more Health
//			} // ends healthcount IF
//		} // ends DistanceCheck If
//	}// Ends AngleCheck IF
//}// Ends Function Checking4Collision


bool initDirect3D(HWND hwnd)
{
	if( NULL == ( pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
	{
		lastResult = E_FAIL;
		return false;
	}

	D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	d3dpp.BackBufferCount  = 1;
	d3dpp.BackBufferHeight = 480;
	d3dpp.BackBufferWidth  = 640;
	d3dpp.hDeviceWindow    = hwnd;

    if( FAILED( pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hwnd,
                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                      &d3dpp, &pd3dDevice ) ) )
    {
		lastResult = E_FAIL;
        return false;
    }

	return true;
}


bool initMap()
{
	//let it know that this is the image that is going to be used for a background
	bkgrd = dxMgr->getSurfaceFromBitmap("./zwm.bmp",1800,1800);
	
	if (bkgrd == NULL)
		return false;

	return true;
}

void drawMap(void)
{

	//this is the size of the bitmap image
	src.top = 0;
	src.bottom = src.top + 1800;
	src.left = 0;
	src.right = src.left + 1800;

	//this is how big we want it on screen
	dest.top = 0 + 40;
	dest.bottom = dest.top + SCRN_HEIGHT - 40;
	dest.left = 0;
	dest.right = dest.left + SCRN_WIDTH;

	dxMgr->blitToSurface(bkgrd, &src, &dest);

}
bool initHealth()
{
	//let it know that this is the image that is going to be used for a background
	health= dxMgr->getSurfaceFromBitmap("./Health.bmp",50,50);
	
	if (health == NULL)
		return false;

	return true;

}
void drawHealth()
{
	int HealthCount = MAX_HSPRITES;

	//Max health is actually the player's current health, it wont draw past 
	//the player's current health
	//current health to be implemented =)
	//Hadoken!!!
	

		for (int i = 0; i < HealthCount; i++)
		{
			//this is the size of the bitmap image
			srcH[i].top = 0;
			srcH[i].bottom = srcH[i].top + 50;
			srcH[i].left = 0;
			srcH[i].right = srcH[i].left + 50;

			//this is the position of the object, the top is where its drawn the bottom is where its moved
			destH[i].top = 0;
			destH[i].bottom = destH[i].top + 40;
			destH[i].left = i * 40;
			destH[i].right = destH[i].left + 40;
			
				if (i < MAX_HEALTH)
				{
					destH[i].right = destH[i].left + 40;
				}
					dxMgr->blitToSurface(health, &srcH[i], &destH[i]);
		}
}